除了一般常見的數字、字串等比較簡單的資料類型,Python 中可以通過組合一些值,來得到多種複合資料類型。其中最常用的是列表 (list)、字典 (dictionary)、元組 (tuple)與集合(Set)。
列表 是 Python 中使用最頻繁的資料類型。
>>> list1 = [1, 4, 9, 16, "Hello"]
>>> list1
[1, 4, 9, 16, 'Hello']
>>> list1[0]
1
>>> list1[-3:]
[9, 16, 'Hello']
當我們把一個**物件賦值 (Assignment)**給一個新的變數時,賦與的其實是該物件的在記憶體中的地址,而不是陣列中的資料,也就是兩個物件指向的是同一個儲存空間,無論哪個物件發生改變,其實都是改變的儲存空間的內容,因此,兩個物件是連動的。深拷貝 (Deep copy) 和 淺拷貝 (Shallow copy) 是只針對物件 (Object) 和陣列 (Array) 這樣的引用資料類型的。
淺拷貝只複製指向某個物件的指標,而不複製物件本身,新舊物件還是共享同一塊記憶體。但深拷貝會另外創造一個一模一樣的物件,新物件跟原物件不共享記憶體,修改新物件不會改到原物件。
圖 1. 賦值、淺拷貝與深拷貝比較
因為列表就是一個陣列,讓我們來看一下這三個操作的差異。
>>> # 賦值範例,可以發現最後兩個變數的位址是一樣的
>>> list1 = [1, 4, 9, 16, [1,3,5]]
>>> assign1 = list1
>>> assign1[0] = 30
>>> assign1[4][1] = 10
>>> print(assign1," address = ",id(assign1))
[30, 4, 9, 16, [1, 10, 5]] address = 2079473843328
>>> print(list1," address = ",id(list1))
[30, 4, 9, 16, [1, 10, 5]] address = 2079473843328
以下為淺拷貝範例,淺拷貝會複製指向某個物件的指飆,以及該物件第一層的所有資料,並形成一個新物件,最後兩個變數的位址是不一樣的。所以,可以發現第一個值 1 在淺拷貝列表 shallow1 中有改變為 30 ,但原列表 list1 中沒有;但當改變列表中的列表 1,3,5 的中間那個值 3 -> 10 時,兩個列表顯示出來的結果都相同,因為嵌套列表的指標指向相同的位址。
>>> # 淺拷貝範例
>>> list1 = [1, 4, 9, 16, [1,3,5]]
>>> shallow1 = list1.copy()
>>> shallow1[0] = 30
>>> shallow1[4][1] = 10
>>> print(shallow1," address = ",id(shallow1))
[30, 4, 9, 16, [1, 10, 5]] address = 2079473843392
>>> print(list1," address = ",id(list1))
[1, 4, 9, 16, [1, 10, 5]] address = 2079473657728
以下為深拷貝範例,創造一個一模一樣的物件,新物件跟原物件不共享記憶體,最後兩個變數的位址是不一樣的。所以,可以發現所有的改變都不會影響到原列表。
>>> # 深拷貝範例
>>> import copy
>>> list1 = [1, 4, 9, 16, [1,3,5]]
>>> deep1 = copy.deepcopy(list1)
>>> deep1[0] = 30
>>> deep1[4][1] = 10
>>> print(deep1," address = ",id(deep1))
[30, 4, 9, 16, [1, 10, 5]] address = 2079473658560
>>> print(list1," address = ",id(list1))
[1, 4, 9, 16, [1, 3, 5]] address = 2079473843712
指向原資料 | 第一層資料為基本資料類型 | 元資料中包含子物件 | |
---|---|---|---|
賦值 | 是 | 會同時改變 | 會同時改變 |
淺拷貝 | 否 | 不會同時改變 | 會同時改變 |
深拷貝 | 否 | 不會同時改變 | 不會同時改變 |
表 1. 賦值、淺拷貝與深拷貝比較表 |
根據 Python 官方說明,所有的切片操作都返回一個新列表,這個新列表包含所需要的元素,這個新列表是一個新的淺拷貝。此外根據剛才的操作,與不可修改 (immutable) 的字符串不同, 列表是一個 可修改 (mutable) 類型,就是說,它自己的內容可以改變。
>>> list1 = [1, 4, 9, 16, 25]
>>> list2 = list1[:] # 淺拷貝
>>> list3 = list1 # 賦值
>>> print(id(list1),id(list2), id(list3))
2079473658304 2079473657856 2079473658304
>>> list2[0] = 30
>>> list1 = [1, 4, 9, 16, 25]
>>> list1.append([1,3,5])
>>> list1
[1, 4, 9, 16, 25, [1, 3, 5]]
>>> list1.extend([1,3,5]) # 會將陣列展開為一串數字
>>> list1
[1, 4, 9, 16, 25, [1, 3, 5], 1, 3, 5]
>>> list1.remove([1,3,5])
>>> list1
[1, 4, 9, 16, 25, 1, 3, 5]
>>> list1 = list1[:5]
>>> list1.insert(1,4)
>>> list1
[1, 4, 9, 16, 25, 36]
>>> list1.pop(1)
4
>>> list1
[1, 9, 16, 25, 36]
>>> list1.reverse()
>>> list1
[36, 25, 16, 9, 1]
>>> list1.sort()
>>> list1
[1, 9, 16, 25, 36]
字典是 Python 的內建資料類型之一,它定義了鍵和值之間一對一的關係。
>>> # 字典有三種賦值方法蓊
>>> dic = {"program":"Python", "database":"mysql"}
>>> dic = dict(program = "Python", database = "mysql")
>>> dic = dict([("program","Python"), ("database","mysql")])
>>> dic
{'program': 'Python', 'database': 'mysql'}
>>> dic["program"]
'Python'
>>> dic["Python"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Python'
>>> dic["Program"] = "Java"
>>> dic
{'program': 'Python', 'database': 'mysql', 'Program': 'Java'}
字典的常用操作
>>> dic = {"program":"Python", "database":"mysql"}
>>> dic2 = dic.copy()
>>> print(id(dic),id(dic2))
2079473853760 2079468906240
>>> dic.keys()
dict_keys(['program', 'database'])
>>> dic.values()
dict_values(['Python', 'mysql'])
>>> dic.items()
dict_items([('program', 'Python'), ('database', 'mysql')])
>>> del(dic["program"])
>>> dic
{'database': 'mysql'}
>>> dic.clear()
>>> dic
{}
>>> t = (1, "mysql", "Python")
>>> t
(1, 'mysql', 'Python')
>>> t[0]
1
>>> t[-1]
'Python'
>>> t[1:3]
('mysql', 'Python')
使用元組有什麼好處
Python 包含有集合類型。集合是由不重複元素組成的無序集合。它的基本用法包括成員檢測和消除重複元素。集合物件也支持像聯合,交集,差集,對稱差集等數學運算。大括號或 set() 函數可以用來創建集合。注意:要創建一個空集合你只能用 set() 而不能用 {},因為後者是創建一個空字典。
>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket) # 消除重複元素 'orange', 'apple'
{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket # 判斷元素內容
True
>>> 'crabgrass' in basket
False
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a # 不重複元素組成
{'a', 'r', 'b', 'c', 'd'}
>>> b
{'c', 'm', 'z', 'l', 'a'}
>>> a - b # a, b 差集
{'r', 'd', 'b'}
>>> a | b # a, b 聯合
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b # a, b 交集
{'a', 'c'}
>>> a ^ b # a, b 對稱差集,只在 a 集合或是 b 集合的字元
{'r', 'd', 'b', 'm', 'z', 'l'}